package org.mozilla.javascript.tools.shell;

import java.io.PrintStream;
import org.mozilla.javascript.*;
import org.mozilla.javascript.tools.ToolErrorReporter;

public class RhinoShell {

    public ShellContextFactory shellContextFactory;
    public final Global global;
    protected ToolErrorReporter errorReporter;

    public RhinoShell(PrintStream out, PrintStream err) {
        global = new Global();
        global.setOut(out);
        global.setErr(err);
        shellContextFactory = new ShellContextFactory();
        shellContextFactory.setOptimizationLevel(-1);
    }

    class IProxy implements ContextAction, QuitAction {

        private String fileName;

        IProxy(String fileName) {
            this.fileName = fileName;
        }

        public Object run(Context cx) {
            processSource(cx, fileName);
            return null;
        }

        public void quit(Context cx, int exitCode) {
        }
    }

    public void runTest(String testFileContent) {
        errorReporter = new ToolErrorReporter(false, global.getErr());
        shellContextFactory.setErrorReporter(errorReporter);

        if (!global.initialized) {
            global.init(shellContextFactory);
        }

        IProxy iproxy = new IProxy(testFileContent);
        shellContextFactory.call(iproxy);
    }

    public void processSource(Context cx, String testFileContent) {
        Script script = loadScriptFromSource(cx, testFileContent, "runner.js");
        if (script != null) {
            evaluateScript(script, cx);
        }
        System.gc();
    }

    public Script loadScriptFromSource(Context cx, String scriptSource, String path) {
        try {
            return cx.compileString(scriptSource, path, 1, null);
        } catch (EvaluatorException e) {
            Context.reportError(e.getMessage());
        } catch (RhinoException e) {
            ToolErrorReporter.reportException(cx.getErrorReporter(), e);
        } catch (VirtualMachineError ex) {
            ex.printStackTrace();
            String msg = ToolErrorReporter.getMessage("msg.uncaughtJSException", ex.toString());
            Context.reportError(msg);
        }
        return null;
    }

    public Object evaluateScript(Script script, Context cx) {
        try {
            return script.exec(cx, global);
        } catch (RhinoException rex) {
            ToolErrorReporter.reportException(cx.getErrorReporter(), rex);
        } catch (VirtualMachineError ex) {
            ex.printStackTrace();
            String msg = ToolErrorReporter.getMessage("msg.uncaughtJSException", ex.toString());
            Context.reportError(msg);
        }
        return Context.getUndefinedValue();
    }

}
